package cn.com.heaton.bleLib.logic.command;

import android.os.Handler;

import java.util.LinkedList;

import cn.com.heaton.bleLib.ble.L;

/**
 * https://github.com/xpg/GizwitsBLE/blob/master/BleLibrary/src/com/xtremeprog/sdk/ble/BleService.java
 * Created by LiuLei on 2017/11/6.
 */
public class BleCommandQueue implements CommandQueue {

    private String TAG = "BleCommandQueue";
    private LinkedList<Command> mCmdList = new LinkedList<>();
    private Handler mHandler = new Handler();

    private Command mCurCmd;

    @Override
    public void add(Command command) {
        synchronized (mCmdList) {
            mCmdList.add(command);
            processNextRequest();
        }
    }

    /**
     * 把数据添加到队列前面
     *
     * @param command
     */
    private void addCommandToFront(Command command) {
        synchronized (mCmdList) {
            mCmdList.addFirst(command);
        }
    }

    @Override
    public void next() {
        mHandler.removeCallbacksAndMessages(null);
        mCurCmd = null;
        processNextRequest();
    }

    @Override
    public boolean isEmpty() {
        return mCmdList == null || mCmdList.size() == 0;
    }

    private int mFailCount = 0;

    /**
     * 执行下一条指令
     */
    private synchronized void processNextRequest() {
        if (mCurCmd != null) {//表示指令还在执行中
            return;
        }
        if (mCmdList.isEmpty()) {//表示没有需要执行的指令了
            return;
        }
        //拿到需要执行的指令
        mCurCmd = mCmdList.remove();
        //开启一个倒计时的等待，发起命令超时
        //执行指令的内容
        boolean result = mCurCmd.execute();
        if (!result) {
            //如果发送指令失败
            //移除超时指令
            mHandler.removeCallbacksAndMessages(null);
            //把指令添加到列表的头部，延迟200ms重新发送，最多重试3次，超过3次就抛弃。
            if (mFailCount < 4) {
                mFailCount++;
                L.i(TAG, "发送指令失败,失败次数" + mFailCount);
                addCommandToFront(mCurCmd);
                mCurCmd = null;
                //间隔100ms之后重新尝试
                mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        processNextRequest();
                    }
                }, 200);
            } else {
                //抛弃上一条指令，开始吓一条指令
                mFailCount = 0;
                mCurCmd = null;
                processNextRequest();
            }
        } else {
            //指令发送成功了，设置超时
            mHandler.postDelayed(mTimeoutRunnable, 10000);
            mFailCount = 0; //重置错误次数
        }
    }

    private Runnable mTimeoutRunnable = new Runnable() {
        @Override
        public void run() {
            //如果一个是空，那么直接报错还是继续下一条指令，这个超时要在这里处理还是
            L.i(TAG, "发送指令失败，跳过这条指令");
            mCurCmd = null;
            processNextRequest();
        }
    };
}
